package com.jin.webvideo.base.spring.resource;

import com.jin.webvideo.base.util.HttpClientUtil;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.URI;

public class HttpRangeInputStream extends InputStream {
    protected static final Logger logger = LoggerFactory.getLogger(HttpRangeInputStream.class);

    // 当前位置
    private long position;
    // 需要读取的长度
    private long length;
    // 文件长度 / 响应报文（响应体）的总长度
    private long fileLength;
    // 是否支持random
    private boolean supportRandom;

    private HttpClient httpClient;
    private InputStream inputStream;
    private HttpResponse resp;
    private HttpGet get;

    public HttpRangeInputStream(URI uri, long length, HttpClient httpClient) throws IOException {
        this.get = new HttpGet(uri);
        get.setHeader("Referrer-Policy", "no-referrer");
        get.setHeader("Cache-Control", "max-age=0, no-cache, no-store, must-revalidate");

        HttpHead head = new HttpHead(uri);
        head.setHeader("Range", "bytes=0-");

        this.httpClient = httpClient;
        resp = this.httpClient.execute(head);
        int code = resp.getStatusLine().getStatusCode();
        String len = resp.getFirstHeader("content-length").getValue();
        HttpClientUtil.close(resp);

        logger.debug("response from {}, code={} contentLength={} length={}", uri, code, len, length);
        if (code == 200 || code == 206) {
            // 206 为支持range
            supportRandom = (code == 206);
            this.fileLength = Long.valueOf(len);
            this.length = Math.min(length, fileLength);
            return;
        }
        throw new IOException("无效的uri");
    }

    @Override
    public long skip(long n) throws IOException {
        // 不支持random直接初始化inputstream
        if (!supportRandom) {
            initStream();
        }
        // 结束位置
        long end = position + n;
        long skip = (end > fileLength ? fileLength - position : n);
        if (inputStream != null) {
            skip = inputStream.skip(n);
        }
        this.position += skip;
        return skip;
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        initStream();
        int c = inputStream.read(b, off, len);
        if (c != -1) {
            this.position += c;
        }
        return c;
    }

    @Override
    public int read() throws IOException {
        initStream();
        int c = inputStream.read();
        if (c != -1) {
            this.position++;
        }
        return c;
    }

    @Override
    public void close() throws IOException {
        HttpClientUtil.close(this.resp);
        get.releaseConnection();
        logger.debug("close {}", get.getURI());
    }

    // 初始化stream
    private void initStream() throws IOException {
        if (inputStream == null) {
            logger.debug("connect to {} range: bytes={}-{} ", get.getURI(), this.position, (position + length - 1));
            get.setHeader("Range", "bytes=" + this.position + "-" + (position + length - 1));
            this.resp = this.httpClient.execute(get);

            this.inputStream = resp.getEntity().getContent();
            String len = resp.getFirstHeader("content-length").getValue();
            logger.debug("connected {} content-length: {} len: {}", get.getURI(), len, this.length);
        }
    }
}
